﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Shop.Crawler.PluginCore;
using Shop.Crawler.PluginAttribute;
using System.IO;
using System.Threading;
using Shop.Crawler.Config;
using Shop.Crawler.Libs;
using System.Collections;

namespace Shop.Crawler
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        #region Threading
        // threads array
        private Thread[] threadsRun;

        // flag to be used to stop all running threads when user request to stop
        bool ThreadsRunning;

        // number of running threads
        private int nThreadCount;
        private int ThreadCount
        {
            get { return nThreadCount; }
            set
            {
                Monitor.Enter(this.lstProcess);
                try
                {
                    for (int nIndex = 0; nIndex < value; nIndex++)
                    {
                        // check if thread not created or not suspended
                        if (threadsRun[nIndex] == null || threadsRun[nIndex].ThreadState != ThreadState.Suspended)
                        {
                            // create new thread
                            threadsRun[nIndex] = new Thread(new ThreadStart(ThreadRunFunction));
                            // set thread name equal to its index
                            threadsRun[nIndex].Name = nIndex.ToString();
                            // start thread working function
                            threadsRun[nIndex].Start();
                            // check if thread dosn't added to the view
                            if (nIndex == this.lstProcess.Items.Count)
                            {
                                // add a new line in the view for the new thread
                                ListViewItem item = this.lstProcess.Items.Add((nIndex + 1).ToString(), 0);
                                string[] subItems = { "", "", "", "0", "0%" };
                                item.SubItems.AddRange(subItems);
                            }
                        }
                        // check if the thread is suspended
                        else if (threadsRun[nIndex].ThreadState == ThreadState.Suspended)
                        {
                            // get thread item from the list
                            ListViewItem item = this.lstProcess.Items[nIndex];
                            item.ImageIndex = 1;
                            item.SubItems[2].Text = "Resume";
                            // resume the thread
                            threadsRun[nIndex].Resume();
                        }
                    }
                    // change thread value
                    nThreadCount = value;
                }
                catch (Exception)
                {
                }
                Monitor.Exit(this.lstProcess);
            }
        }

        void ThreadRunFunction()
        {
            //MyWebRequest request = null;
            while (ThreadsRunning && int.Parse(Thread.CurrentThread.Name) < this.ThreadCount)
            {
                string uri = string.Empty;// DequeueUri();
                if (uri != null)
                {
                    //                     if (SleepConnectTime > 0)
                    //                         Thread.Sleep(SleepConnectTime * 1000);
                    //                    ParseUri(uri, ref request);
                }
                else
                    Thread.Sleep(Settings.SLEEP_FETCH_TIME * 1000);
            }

            Monitor.Enter(this.lstProcess);
            try
            {
                ListViewItem item = this.lstProcess.Items[int.Parse(Thread.CurrentThread.Name)];
                if (ThreadsRunning == false)
                    item.SubItems[2].Text = "Stop";
                item.ImageIndex = 0;
            }
            catch (Exception)
            {
            }
            Monitor.Exit(this.lstProcess);
        }

        #endregion

        #region Queueing
        // binary tree to keep unique Uri's
        private SortTree urlStorage { set; get; }

        // unique Uri's queue
        private Queue queueURLS { set; get; }

        // push uri to the queue
        bool EnqueueUri(string uri, bool bCheckRepetition)
        {
            // add the uri to the binary tree to check if it is duplicated or not
            if (bCheckRepetition == true && AddURL(ref uri) == false)
                return false;

            Monitor.Enter(queueURLS);
            try
            {
                // add the uri to the queue
                queueURLS.Enqueue(uri);
            }
            catch (Exception)
            {
            }
            Monitor.Exit(queueURLS);

            return true;
        }

        // pop uri from the queue
        string DequeueUri()
        {
            Monitor.Enter(queueURLS);
            string uri = null;
            try
            {
                uri = queueURLS.Dequeue().ToString();
            }
            catch (Exception)
            {
            }
            Monitor.Exit(queueURLS);
            return uri;
        }

        bool AddURL(ref string uri)
        {
            Monitor.Enter(urlStorage);
            bool bNew = false;
            try
            {
                bNew = urlStorage.Add(ref uri).Count == 1;
            }
            catch (Exception)
            {
            }
            Monitor.Exit(urlStorage);

            return bNew;
        }

        #endregion

        private void stbRun_Click(object sender, EventArgs e)
        {
            //StartParsing("http://victoriasecret.com", typeof());
            foreach (RobotNet robot in HostProvider.Robots)
            {
                object[] arr = robot.GetType().GetCustomAttributes(typeof(RobotPluginAttribute), true);

            }
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            DirectoryInfo dInfo = new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "Plugins"));
            if (dInfo.Exists)
            {
                FileInfo[] files = dInfo.GetFiles("*.dll");
            }
            else
            {
                Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "Plugins"));
                MessageBox.Show("Please update plugins");
            }
        }
    }
}
